#pragma once
#include <iostream>
#include "NesPpu.h"

struct InterruptVectors
{
	uint16_t NMI;
	uint16_t Reset;
	uint16_t IRQ_BRK;
};

struct CpuRegister
{
	uint16_t programCounter = 0;
	uint8_t status = 0;
	uint8_t accmulator = 0;
	uint8_t xIndex = 0;
	uint8_t yIndex = 0;
	uint8_t stackPointer = 0;

	uint8_t reserved;//占位
};

class NesCpu
{
private:
	uint8_t* memory = nullptr;

	//bank size == 0x2000
	uint8_t* banks[8] = { nullptr };

	/*
	* 0x0000 - 0x07ff : 2KB internal RAM
	* 0x0800 - 0x1fff : Mirrors of $0000-$07FF
	*/
	uint8_t* mainMemory			= nullptr;

	/*
	* 0x2000 - 0x2007 : NES PPU registers
	* 0x2008 - 0x3fff : Mirrors of $2000-2007 (repeats every 8 bytes)
	*/
	uint8_t* ppuRegistersMemory	= nullptr;

	/*
	* 0x4000 - 0x4017 : NES APU and I/O registers
	* 0x4018 - 0x401f : APU and I/O functionality that is normally disabled
	* 0x4020 - 0x5fff : else
	*/
	uint8_t* extRegisterAndRom	= nullptr;

	/*
	* 0x6000 - 0x7fff : Battery Backed Save or Work RAM (SRAM)
	*/
	uint8_t* sramMemory			= nullptr;

	//输入流内部状态
	uint8_t buttonStreamP1 = 0;
	uint8_t buttonStreamP2 = 0;
	uint8_t strobeFlag = 0;

	InterruptVectors iv;
	CpuRegister registers;

	NesPpu* ppu = nullptr;

	uint8_t Band2Read(uint16_t address);
	void Band2Write(uint16_t address, uint8_t v);
	void WriteSpritDataDMA(uint16_t  address, uint8_t v);
public:

	bool Init(uint8_t prgRomSize,uint8_t* prgRomData,uint8_t chrRomSize,uint8_t* chrRomData);

	uint8_t Read(uint16_t address);
	void Write(uint16_t address, uint8_t v);

	void Push(uint8_t v);
	uint8_t Pop();

	void PrintIV();
	const InterruptVectors& GetInterruptVectors();
	CpuRegister* GetRegister();
	NesPpu* GetPpu();

	void Free();

	//按键状态
	//A B Select Start Up Down Left Right * 2(2个控制器)  
	uint8_t buttonStatus[16] = { 0 };
};

